using Digitalmes.Domain.Entities.Mes.Processes;

namespace Digitalmes.Application.Services.Impl;

/// <summary>
/// 工艺路线查询服务实现。
/// </summary>
internal sealed class RoutingQueryService(IRepository<ProcRouting> routingRepo) : IRoutingQueryService
{
    private ProcRouting? _routing;

    /// <summary>
    /// 检查工位是否为对应工艺路线的首站。
    /// </summary>
    /// <param name="routingId">工艺路线 Id</param>
    /// <param name="workstationId">工位 Id</param>
    /// <returns></returns>
    public async Task<bool> IsFirstWorkstationAsync(long routingId, long workstationId)
    {
        var routing = await GetRoutingAsync(routingId);
        var step = routing!.Steps.OrderBy(m => m.Seq).First();
        return step.Operation?.WsIds.Contains(workstationId) == true;
    }

    /// <summary>
    /// 检查工位是否为对应工艺路线的首站。
    /// </summary>
    /// <param name="productId">产品 Id</param>
    /// <param name="lineId">产线 Id</param>
    /// <param name="workstationId">工位 Id</param>
    /// <returns></returns>
    public async Task<bool> IsFirstWorkstationAsync(long productId, long lineId, long workstationId)
    {
        var routing = await GetRoutingAsync(productId, lineId);
        var step = routing!.Steps.OrderBy(m => m.Seq).First();
        return step.Operation?.WsIds.Contains(workstationId) == true;
    }

    /// <summary>
    /// 检查工序是否为对应工艺路线的尾站。
    /// </summary>
    /// <param name="routingId">工艺路线 Id</param>
    /// <param name="operationId">工序 Id</param>
    /// <returns></returns>
    public async Task<bool> IsFirstOperationAsync(long routingId, long operationId)
    {
        var routing = await GetRoutingAsync(routingId);
        var step = routing!.Steps.OrderBy(m => m.Seq).First();
        return step.Operation?.Id == operationId;
    }

    /// <summary>
    /// 检查工序是否为对应工艺路线的尾站。
    /// </summary>
    /// <param name="routingId">工艺路线 Id</param>
    /// <param name="operationId">工序 Id</param>
    /// <returns></returns>
    public async Task<bool> IsLastOperationAsync(long routingId, long operationId)
    {
        var routing = await GetRoutingAsync(routingId);
        var step = routing!.Steps.OrderBy(m => m.Seq).Last();
        return step.Operation?.Id == operationId;
    }

    /// <summary>
    /// 获取工艺步骤。
    /// </summary>
    /// <param name="routingId">工艺路线 Id</param>
    /// <param name="operationId">工序 Id</param>
    /// <returns></returns>
    public async Task<ProcRoutingStep> GetRoutingStepAsync(long routingId, long operationId)
    {
        var routing = await GetRoutingAsync(routingId);
        return routing!.Steps.First(m => m.OperationId == operationId);
    }

    /// <summary>
    /// 获取工艺步骤。
    /// </summary>
    /// <param name="productId">产品 Id</param>
    /// <param name="lineId">产线 Id</param>
    /// <param name="workstationId">工位 Id</param>
    /// <returns></returns>
    public async Task<ProcRoutingStep?> GetRoutingStepAsync(long productId, long lineId, long operationId)
    {
        var routing = await GetRoutingAsync(productId, lineId);
        if (routing == null)
        {
            return null;
        }

        return routing.Steps.FirstOrDefault(m => m.OperationId == operationId);
    }

    /// <summary>
    /// 获取当前工序前最近的关键工艺步骤。
    /// </summary>
    /// <param name="routingId">工艺路线 Id</param>
    /// <param name="operationId">工序 Id</param>
    /// <returns></returns>
    public async Task<ProcRoutingStep?> GetLastCriticalStepAsync(long routingId, long operationId)
    {
        var routing = await GetRoutingAsync(routingId);
        var step = routing!.Steps.First(m => m.OperationId == operationId);
        return routing.Steps.OrderBy(m => m.Seq).Where(m => m.Seq < step.Seq && m.IsCritical).LastOrDefault();
    }

    /// <summary>
    /// 获取工艺路线结构体对象。
    /// </summary>
    /// <param name="routingId">工艺路线 Id</param>
    /// <returns></returns>
    private async Task<ProcRouting?> GetRoutingAsync(long routingId)
    {
        _routing ??= await routingRepo.AsQueryable()
                .Includes(m => m.Steps, x => x.Operation)
                .Where(m => m.Id == routingId)
                .FirstOrDefaultAsync();
        return _routing;
    }

    private async Task<ProcRouting?> GetRoutingAsync(long productId, long lineId)
    {
        // 产线+工位找到对应工序，产品+产线找到对应工艺路线

        _routing ??= await routingRepo.AsQueryable()
                .Includes(m => m.Steps, x => x.Operation)
                .Where(m => m.ProductId == productId && m.LineId == lineId)
                .FirstOrDefaultAsync();
        return _routing;
    }
}
